#ifdef UNIX
# define _GNU_SOURCE /* for vasprintf */
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "main.h"
#include "logwin.h"

GtkTextBuffer *buf;
GtkWidget *textview;
GtkWidget *logwin;

GtkTextTag *tags[3];

typedef enum
{
    TEXTTAG_RED,
    TEXTTAG_ORANGE,
    TEXTTAG_BLACK
} TextTag;

G_MODULE_EXPORT void ch_dbglvl(GtkWidget *combo)
{
    debug_level = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
}

G_MODULE_EXPORT void logwin_toggle(GtkWidget *check_item)
{
    if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(check_item)))
        gtk_widget_show(logwin);
    else
        gtk_widget_hide(logwin);
}

void logwin_init(GtkBuilder *builder)
{
    GtkWidget *combo;
    GtkListStore *store;
    GtkCellRenderer *cell;
    GdkColor color;
    u8 i;

    /* the logging window */
    logwin = GTK_WIDGET(gtk_builder_get_object(builder, "logwin"));

    /* the textview */
    textview = GTK_WIDGET(gtk_builder_get_object(builder, "log_textview"));
    buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview));
    /* textview style */
    gdk_color_parse("red", &color);
    gtk_text_buffer_create_tag(buf, "color_error", "foreground-gdk", &color, NULL);
    gdk_color_parse("orange", &color);
    gtk_text_buffer_create_tag(buf, "color_warning", "foreground-gdk", &color, NULL);
    gdk_color_parse("black", &color);
    gtk_text_buffer_create_tag(buf, "color_unknown", "foreground-gdk", &color, NULL);

    /* the debug level combo box */
    combo = GTK_WIDGET(gtk_builder_get_object(builder, "log_combo"));

    /* creates it as with gtk_combo_box_new_text() */
    store = gtk_list_store_new(1, G_TYPE_STRING);
    gtk_combo_box_set_model(GTK_COMBO_BOX(combo), GTK_TREE_MODEL(store));
    g_object_unref(store);

    cell = gtk_cell_renderer_text_new();
    gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), cell, TRUE);
    gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo), cell, "text", 0, NULL);

    /* sets the choices and the signal */
    for (i = 0; i < NUMDBGLVL; i++)
        gtk_combo_box_append_text(GTK_COMBO_BOX(combo), dbgLvlName[i]);
    gtk_combo_box_set_active(GTK_COMBO_BOX(combo), debug_level);

    /* displays all the window */
    gtk_widget_show_all(logwin);
}

void logwin_log(DbgLvl lvl, DbgType cat, const char *format, va_list ap)
{
    GtkTextIter end;
    GtkTextMark *mark;
    char *startdbg, *maindbg, *txt;
    GtkTextTag *tag;
    s32 mainSize;
#ifndef UNIX
    s32 size = 10;
    s32 n;
#endif

    gdk_threads_enter();

    startdbg = malloc(strlen(dbgTypeName[cat]) + 3);
    sprintf(startdbg, "%s: ", dbgTypeName[cat]);

#ifdef UNIX
    mainSize = vasprintf(&maindbg, format, ap);
#else
    maindbg = malloc(size);

    while (1)
    {
        n = vsnprintf(maindbg, size, format, ap);
        if (n > -1 && n < size) /* string of size 'size' is valid */
            break;

        size *= 2; /* not valid: try to double the size */
        maindbg = realloc(maindbg, size);
    }
    mainSize = strlen(maindbg);
#endif

    txt = malloc(strlen(startdbg) + mainSize + 2);
    txt[0] = '\0';
    strcpy(txt, startdbg);
    strcat(txt, maindbg);
    strcat(txt, "\n");

    free(startdbg);
    free(maindbg);

    switch (lvl)
    {
    case ERR:
        tag = tags[TEXTTAG_RED];
        break;
    case WRN:
        tag = tags[TEXTTAG_ORANGE];
        break;
    default:
        tag = tags[TEXTTAG_BLACK];
        break;
    }

    gtk_text_buffer_get_end_iter(buf, &end);
    gtk_text_buffer_insert_with_tags(buf, &end, txt, -1, tag, NULL);
    gtk_text_buffer_get_end_iter(buf, &end);
    mark = gtk_text_buffer_create_mark(buf, NULL, &end, FALSE);
    gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(textview), mark);
    gtk_text_buffer_delete_mark(buf, mark);

    free(txt);

    gdk_threads_leave();
}

